///////////////////////////////////////////////////////////////////////////////
// File:        Player.hpp
// Author:      671643387@qq.com
// Description:
///////////////////////////////////////////////////////////////////////////////

#ifndef MONKEY_COMMON_PLAYER_PLAYER_HPP_
#define MONKEY_COMMON_PLAYER_PLAYER_HPP_

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif

#include <malloc.h>
#include <memory.h>
#include <cassert>
#include <deque>
#include "common/TcpConnection.hpp"

namespace monkey
{
    namespace common
    {
        namespace player
        {
            class Player : public TcpConnection
            {
            public:
                typedef TcpConnection   Parent;
                typedef Player          Self;

            public:
                Player(int id);
                ~Player(void);

                ///////////////////////////////////////////////////////////////

            public:
                ///////////////////////////////////////////////////////////////
                int GetID(void) const { return id_; }

                void Send(const char* data, size_t length);

            protected:
                virtual bool OnRead(void);
                virtual bool OnWrite(void);
                virtual void OnClose(void);

                ///////////////////////////////////////////////////////////////

                bool SendPending(const char* data, size_t length);

                ///////////////////////////////////////////////////////////////

            protected:
                int id_;

            private:
                ///////////////////////////////////////////////////////////////

                class WriteBuffer
                {
                public:
                    WriteBuffer(void)
                        : data_(NULL)
                        , size_(0)
                        , rpos_(0)
                    {

                    }

                    ~WriteBuffer(void)
                    {
                        if (data_)
                            free((void*)data_);
                    }

                    bool Fill(const char* data, size_t size)
                    {
                        assert(!data_);
                        data_ = (char*)malloc(size);
                        if (!data_)
                            return false;

                        this->size_ = size;
                        this->rpos_ = 0;
                        memcpy(this->data_, data, size);
                        return true;
                    }

                    bool Send(TcpConnection* conn)
                    {
                        assert(conn);
                        conn->NotifyWrite();
                        int ret = conn->Write(data_, (size_ - rpos_));
                        if (ret != SOCKET_ERROR)
                        {
                            if (ret != SOCKET_ERROR_WOULDBLOCK)
                            {
                                rpos_ += (size_t)ret;
                            }
                            return true;
                        }
                        return false;
                    }

                    bool Empty(void)
                    {
                        assert(size_ > 0);
                        return (size_ == rpos_);
                    }
                private:
                    char*       data_;
                    size_t      size_;
                    size_t      rpos_;
                };

                typedef std::deque<WriteBuffer*> WriteBufferQueue;

                ///////////////////////////////////////////////////////////////

            private:
                ///////////////////////////////////////////////////////////////

                WriteBufferQueue writebuffs_;
            };
        }
    }
}

#endif /* MONKEY_COMMON_PLAYER_PLAYER_HPP_ */
